// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: some helper functions for working with the internet.
//   $Id$




#include "stdafx.h"
#include "inetFunc.h"

	
	HRESULT fetchHTTPDocument(BSTR sURLCurrent,BSTR sURLRel,BSTR * psText)
	{
		CComBSTR bs;
		bs.Attach(Relative2AbsolutePath(sURLCurrent, sURLRel));
		return fetchHTTPDocument(bs, psText);
	}



HINTERNET getURLHandle(HINTERNET HINet, BSTR sURL,DWORD * pdwReturnCode)
{
	HINTERNET HIURL = 
		::InternetOpenUrlW(
			HINet,
			_bstr_t(sURL),
			L"",
			0,
			INTERNET_FLAG_NO_UI,
			1
			);
		
	if(HIURL)
	{
		//check the status
		DWORD len = 4;
		DWORD ix = 0;
		HttpQueryInfo
		(
			HIURL,
			HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
			pdwReturnCode,
			&len,
			&ix
		);
	}
	return HIURL;
}



#define TEXTBUFFERSIZE 8192
	HRESULT fetchHTTPDocument(BSTR sURL,BSTR * psText)
	{
		HRESULT hr;
		//open connection to URL
		HINTERNET HINet = OpenInternetHandle();
		CComBSTR sbigBuf;

		if(HINet!=NULL)
		{
			HINTERNET HIURL;
			DWORD code;
			HIURL = getURLHandle(HINet, sURL,&code);
			if((code >= 200 && code < 300) || code == 304)
			{
				//get the text from the internet document	
				char * szBuf = new char[TEXTBUFFERSIZE + 1];
				DWORD dwBytesRead;
				DWORD dwBigBufSize = 0;

				BOOL BSuc;
				//hold the last char in case size of szBuf is wrong.
				char cTemp = szBuf[TEXTBUFFERSIZE];
				do
				{
					BSuc =
						InternetReadFile(
							HIURL,
							(LPVOID) szBuf,
							TEXTBUFFERSIZE,
							&dwBytesRead
						);
					dwBigBufSize += dwBytesRead;
					szBuf[dwBytesRead] = NULL;
					sbigBuf += szBuf;

				}while(dwBytesRead == TEXTBUFFERSIZE);

				*psText = sbigBuf.Detach();
				//replace last char
				szBuf[TEXTBUFFERSIZE] = cTemp;
				delete[] szBuf;
				hr = S_OK;
			}
			else
			{
				hr = E_FAIL;
			}

			if(HIURL != 0)
				InternetCloseHandle(HIURL);
			InternetCloseHandle(HINet);
			
		}
		else
		{
			hr = E_FAIL;
		}
		return hr;
	}

	// Added for bug 267
	HRESULT fetchHTTPBinaryDocument(BSTR sURL, void **ppBuf, DWORD &dwBufSize)
	{
		HRESULT hr = S_OK;
		if(sURL && ppBuf) {
			HINTERNET HINet = OpenInternetHandle();
			if(HINet != 0) {
				HINTERNET HIURL;
				DWORD code;
				HIURL = getURLHandle(HINet, sURL, &code);
				if(HIURL != 0 && code == 200) {
					dwBufSize = 0;
					const int nBlockSize = 8192;
					*ppBuf = malloc(nBlockSize);
					DWORD dwBytesRead = 0;
					bool bDone = false;
					while(!bDone && *ppBuf) {
						InternetReadFile(HIURL, reinterpret_cast<BYTE *>(*ppBuf) + dwBufSize, nBlockSize, &dwBytesRead);
						dwBufSize += dwBytesRead;
						if(dwBytesRead != nBlockSize)
							bDone = true;
						else
							*ppBuf = realloc(*ppBuf, dwBufSize + nBlockSize);
					}
				} else
					hr = E_FAIL;
				if(HIURL != 0)
					InternetCloseHandle(HIURL);
				InternetCloseHandle(HINet);
			} else
				hr = E_FAIL;
		} else
			hr = E_INVALIDARG;
		return hr;
	}

#undef INETAPPNAME
#undef TEXTBUFFERSIZE


BSTR Relative2AbsolutePath(BSTR sFromDoc, BSTR sRelPath, bool bURLEncode)
{
	wchar_t sReturn[INTERNET_MAX_URL_LENGTH];
	DWORD len = INTERNET_MAX_URL_LENGTH;
	DWORD flags = 0;
	if(!bURLEncode)
	{	
		flags |= ICU_NO_ENCODE;
		if(wcsstr(L"file://",sFromDoc) == 0)
		{
			flags |= ICU_DECODE;
		}
	}
	if(::InternetCombineUrlW(sFromDoc,sRelPath,sReturn,&len,flags))
		return ::SysAllocString(sReturn);
	else
		return ::SysAllocString(sRelPath);

}

//I nicked this from http://www.codeproject.com/useritems/urlencode.asp
//	I will tidy it later and remove  MFC requirement.

inline BYTE toHex(const BYTE &x)
{
	return x > 9 ? x + 55: x + 48;
}

CString URLEncode(CString sIn)
{
	CString sOut;

	const int nLen = sIn.GetLength() + 1;

	register LPBYTE pOutTmp = NULL;
	LPBYTE pOutBuf = NULL;
	register LPBYTE pInTmp = NULL;
	LPBYTE pInBuf =(LPBYTE)sIn.GetBuffer(nLen);
	BYTE b = 0;

	//alloc out buffer
	pOutBuf = (LPBYTE)sOut.GetBuffer(nLen  * 3 - 2);//new BYTE [nLen  * 3];

	if(pOutBuf)
	{
		pInTmp= pInBuf;
		pOutTmp = pOutBuf;

		// do encoding
		while (*pInTmp)
		{
			if(isalnum(*pInTmp))
				*pOutTmp++ = *pInTmp;
			else if(isspace(*pInTmp))
			{
				*pOutTmp++ = '%';
				*pOutTmp++ = '2';
				*pOutTmp++ = '0';
			}
			else
			{
				*pOutTmp++ = '%';
				*pOutTmp++ = toHex(*pInTmp>>4);
				*pOutTmp++ = toHex(*pInTmp%16);
			}
			pInTmp++;
		}
		*pOutTmp = '\0';
		//sOut=pOutBuf;
		//delete [] pOutBuf;
		sOut.ReleaseBuffer();
	}
	sIn.ReleaseBuffer();
	return sOut;
}